<?php

declare(strict_types=1);

namespace App\Chat\Service;

use App\Chat\Dto\ChatLoginDTO;
use App\Chat\Event\ChatLoginAfter;
use App\Chat\Interfaces\ChatUserAuthInterface;
use App\Common\Helpers\Aes;
use App\CustHub\Mapper\ChCustomerServiceMapper;
use App\CustHub\Model\ChCustomerService;
use App\CustHub\Service\ChCustomerServiceService;
use Hyperf\Database\Model\ModelNotFoundException;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Stringable\Str;
use Mine\Annotation\DependProxy;
use Mine\Exception\NormalStatusException;
use Mine\Exception\UserBanException;
use Mine\Helper\MineCode;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ServerRequestInterface;

#[DependProxy(values: [ChatUserAuthInterface::class])]
class ChatLoginService implements ChatUserAuthInterface
{
    #[Inject]
    protected ChCustomerServiceMapper $mapper;

    #[Inject]
    protected SocketClientService $clientService;

    #[Inject]
    protected ChCustomerServiceService $customerService;

    public function autoLogin(array $params): array
    {
        $userinfo = $this->mapper->findById($params['id']);
        if(empty($userinfo)){
            throw new NormalStatusException(t('jwt.login_error'), MineCode::NO_USER);
        }
        $userinfo = $userinfo->toArray();
        try {
            $userLoginAfter = new ChatLoginAfter($userinfo);
            $loginInfo = $this->handleLogin($userinfo, $userLoginAfter);
//            $loginInfo = Aes::encrypt(json_encode($loginInfo));
//            return [
//                'loginInfo' => $loginInfo
//            ];
            return $loginInfo;
        } catch (\Throwable $e) {
            $this->handleException($e);
        }
    }


    public function passwordLogin(ChatLoginDTO $params): array
    {
        $userinfo = $this->mapper->findByAccount($params->getAccount());

        try {
            $userLoginAfter = new ChatLoginAfter($userinfo);
            if (!empty($userinfo) && $this->mapper->checkPass($params->getPassword(), $userinfo['password'])) {
                return $this->handleLogin($userinfo, $userLoginAfter);
            } else {
                $this->handleLoginFailure($userLoginAfter);
            }
        } catch (\Throwable $e) {
            $this->handleException($e);
        }
    }

    private function handleLogin(array $userinfo, ChatLoginAfter $userLoginAfter): array
    {
        if (
            $userinfo['status'] == ChCustomerService::ENABLE
        ) {
            $userLoginAfter->message = t('jwt.login_success');
            $securityKey = md5(Str::uuid()->toString() . $userinfo['id']);
            $userLoginAfter->userinfo['security_key'] = $securityKey;
            $token = chatUser()->getToken($userLoginAfter->userinfo);
            $userLoginAfter->token = $token;
            event($userLoginAfter);
            return [
                'token' => $token,
                'userInfo' => [
                    'id' => $userinfo['id'],
                    'nickname' => $userinfo['name'],
                    'account' => $userinfo['account'],
                ],
                'securityKey' => $securityKey,
            ];
        } else {
            $userLoginAfter->loginStatus = false;
            $userLoginAfter->message = t('jwt.user_ban');
            event($userLoginAfter);
            throw new UserBanException;
        }
    }

    /**
     * 用户退出
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function logout(): bool
    {
        $user = chatUser();
        $userId = $user->getUserInfo(container()->get(ServerRequestInterface::class)->getQueryParams()['token'])['id'];
        $fds[] = $this->clientService->findUserFds($userId);
        foreach ($fds as $fd){
            $this->clientService->unbind($fd);
        }
        $this->customerService->changeOnlineStatus($userId, 0);
        return $user->getJwt()->logout();
    }

    /**
     * 处理登录失败
     *
     * @param ChatLoginAfter $userLoginAfter
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    private function handleLoginFailure(ChatLoginAfter $userLoginAfter): void
    {
        $userLoginAfter->loginStatus = false;
        $userLoginAfter->message = t('jwt.login_error');
        event($userLoginAfter);
        throw new NormalStatusException;
    }

    /**
     * 处理登录过程中的异常
     *
     * @param \Throwable $e
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    private function handleException(\Throwable $e): void
    {
        if ($e instanceof ModelNotFoundException) {
            throw new NormalStatusException(t('jwt.login_error'), MineCode::NO_USER);
        }
        if ($e instanceof NormalStatusException) {
            throw new NormalStatusException(t('jwt.login_error'), MineCode::NO_USER);
        }
        if ($e instanceof UserBanException) {
            throw new NormalStatusException(t('jwt.user_ban'), MineCode::USER_BAN);
        }
        throw new NormalStatusException(t('jwt.unknown_error').$e->getMessage());
    }

}